home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / DNet / DGoDoc.cpp < prev    next >
Text File  |  1996-07-05  |  61KB  |  2,276 lines

  1. // DGopherDoc.cp
  2. // d.g.gilbert
  3.  
  4.  
  5.  
  6.  
  7. #include "DGoDoc.h"
  8. #include "DGoNetDoc.h"
  9.  
  10. #include "DGoAskDoc.h"
  11. #include "DGoPrefs.h"
  12.  
  13. #include <ncbi.h>
  14. #include <dgg.h>
  15. #include <Dvibrant.h>
  16. #include <DApplication.h>
  17. #include <DGopher.h>
  18. #include <DGoList.h>
  19. #include <DGoInit.h>
  20. #include <DGoPlus.h>
  21. #include <DGoClasses.h>
  22. #include <DPanel.h>
  23. #include <DControl.h>
  24. #include <DDialogText.h>
  25. #include <DWindow.h>
  26. #include <DMenu.h>
  27. #include <DFile.h>
  28. #include <DUtil.h>
  29. #include <DIconLib.h> //??
  30. #include <DIcons.h>
  31.  
  32.  
  33. enum ResizeWindSizes {
  34.     kWinDragHeight = 20,
  35.     kWinScrollWidth = 0,   // added to both vert & hor.
  36.     kWinMinWidth = 0,
  37.     kWinExtraHeight= 0
  38.     };
  39.  
  40. /* from vibrant/vibwndws.c */
  41. extern "C" void Nlm_ResizeWindow(Nlm_GraphiC w, Nlm_Int2 dragHeight,
  42.                               Nlm_Int2 scrollWidth, Nlm_Int2 minWidth,
  43.                               Nlm_Int2 extraHeight);
  44. /* for doc window: Nlm_ResizeWindow (w, 20, 0, Nlm_StringWidth (title) + 70, 0); */
  45.  
  46.  
  47. Global  Nlm_RecT  gGopherListDocRect = { 0, 0, 0, 0 };
  48. Global  DGopherListDoc* gGopherDoc = NULL;
  49.  
  50. enum { kGolistViewWidth = 225 };
  51.  
  52. enum DGoDocCmds {
  53.     cProcessGopher = 30346,
  54.     cStuf,
  55.     cStufInline,
  56.     cSave,
  57.     cAdd,
  58.     cProcessInlines
  59.     };
  60.  
  61. char* DGopherListDoc::kGopherDocSuffix = ".go4";
  62.  
  63. Local Nlm_FonT    gSmallFont= NULL;
  64.  
  65. inline void MakeSmallFont()
  66. {
  67.     if (!gSmallFont) 
  68.         gSmallFont = Nlm_GetFont( "Times", 9, false, false, false, "Roman");
  69. }
  70.  
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77.  
  78.  
  79. class DGoDropMenuButton : public DIconButton
  80. {
  81. public:
  82.     DPopupList* fPop;
  83.     
  84.      DGoDropMenuButton(long id, DView* itsSuperior, DIcon* itsIcon, DPopupList* itsPopup);
  85.     virtual void Click(Nlm_PoinT mouse);
  86.     virtual void Release(Nlm_PoinT mouse);
  87.  
  88. };
  89.  
  90. DGoDropMenuButton::DGoDropMenuButton(long id, DView* itsSuperior, 
  91.                                                         DIcon* itsIcon, DPopupList* itsPopup):
  92.         DIconButton( id, itsSuperior, itsIcon),
  93.         fPop(itsPopup)
  94. {
  95. }
  96.  
  97. void DGoDropMenuButton::Click(Nlm_PoinT mouse)
  98. {
  99.     DIconButton::Click(mouse);
  100.     fPop->Show();
  101.     fPop->Invalidate();
  102.     //Nlm_Beep();
  103. }
  104.  
  105. void DGoDropMenuButton::Release(Nlm_PoinT mouse)
  106. {
  107.     fPop->Hide();
  108.     fPop->Invalidate();
  109.     DIconButton::Release(mouse);
  110. #if 0
  111.     Nlm_RecT area;
  112.     this->ViewRect( area);
  113.     if (fFrame) Nlm_InsetRect( &area, kFInset, kFInset);
  114.     Nlm_InvertRect( &area);
  115.     if (Nlm_PtInRect( mouse, &area)) {
  116.         // then button is "selected", otherwise not.
  117.         this->IsMyViewAction(this);
  118.         }
  119. #endif
  120. }
  121.  
  122.  
  123.  
  124.  
  125. //class    DGopherListDoc : public DWindow
  126.  
  127. Boolean DGopherListDoc::gOptionIsOn = false;
  128. Boolean DGopherListDoc::gFetchSingles = true;
  129. DMenu * DGopherListDoc::gViewChoiceMenu = NULL;
  130. DView * DGopherListDoc::gLockWinMenuItem = NULL;
  131.  
  132. Local DGopherList *     gClipGophers = NULL;
  133. Local DGopher       *     gClipGopher = NULL;
  134.  
  135.  
  136. DGopherListDoc::DGopherListDoc( long id) :
  137.         DWindow( id, gApplication) 
  138. {
  139.     Initialize(NULL);
  140.     //fParentlist= new DList(NULL, DList::kDeleteObjects);
  141.     fParentlist= new DList(NULL);
  142.     SetInfoLine();
  143. }
  144.  
  145.  
  146. DGopherListDoc::DGopherListDoc( long id, DGopher* parentGopher) :
  147.         DWindow( id, gApplication)
  148.     Initialize(NULL);
  149.     fParent= parentGopher;
  150.     if (fParent) fParent->newOwner();
  151.     //fParentlist= new DList(NULL, DList::kDeleteObjects);
  152.     fParentlist= new DList(NULL);
  153.     SetInfoLine();
  154. }
  155.  
  156. DGopherListDoc::DGopherListDoc( long id, DGopherList* activeList, char* name) :
  157.         DWindow( id, gApplication) 
  158.     Initialize(name);
  159.  
  160.     //fGolist= activeList;
  161.     // !! clone fGolist !?
  162.     //if (fGolist) fParent= fGolist->fParentMenu;
  163.     //if (fParent) fParent->newOwner();
  164.     //fParentlist= new DList(NULL, DList::kDeleteObjects);
  165.     fParentlist= new DList(NULL);
  166.  
  167.     SetInfoLine();
  168.     this->ReplaceData( activeList); //??
  169. }
  170.  
  171.  
  172. DGopherListDoc::~DGopherListDoc()
  173. {
  174.     if (fGolist) {
  175.         //if (fGolist->GetOwnerCount() <= 1) delete fGolist; else 
  176.         fGolist->suicide();  
  177.         }
  178.     if (fOldlist) {
  179.         //if (fOldlist->GetOwnerCount() <= 1) delete fOldlist; else 
  180.         fOldlist->suicide();  
  181.         }
  182.     if (fParentlist) {
  183.         short i, n= fParentlist->GetSize();
  184.         for (i=0; i<n; i++) {
  185.             short j, m;
  186.             DGopherList* st= (DGopherList*) fParentlist->At(i);
  187.             delete st;
  188.             }
  189.         delete fParentlist;
  190.         }
  191. #if 0
  192.     //if (fParentPop) delete fParentPop;  //noooooooooo ... dview::deletesubviews...
  193.     //if (fGoview) fGoview->suicide();  //noooooooooo ... dview::deletesubviews...
  194.     //if (fParent) fParent->suicide();  // !BOMB BUG -- fParent sometimes (?) in fGolist
  195. #endif
  196. }
  197.  
  198.  
  199. void DGopherListDoc::Initialize( char* name)
  200. {
  201.     fGoview= NULL;
  202.     fGolist= NULL; 
  203.     fOldlist= NULL;
  204.     fStatus= NULL;
  205.     fParentlist= NULL;
  206.     fParent= NULL;
  207.     fInUse= false;
  208.     fPinned= false;
  209.     fFirststuff= 1;
  210.     fParentPop= NULL;
  211.     fStickpin= NULL;
  212.     
  213.     short width= -1, height= -1, left= -10, top= -20; // default window loc
  214.     if (!Nlm_EmptyRect(&gGopherListDocRect))  {
  215. #ifndef TRY_WIN_MOTIF
  216.             // leave out of motif til find bug preventing its' DView::SizeTo...
  217.         width= MAX( 40, gGopherListDocRect.right - gGopherListDocRect.left);
  218.         height= MAX( 50, gGopherListDocRect.bottom - gGopherListDocRect.top);
  219. #endif
  220.         }
  221.     this->InitWindow(document, width, height, left, top, name); 
  222. }
  223.  
  224.  
  225.  
  226. void DGopherListDoc::SetInfoLine()
  227. {
  228.     DPrompt* pr;
  229.     Nlm_PoinT nps, droppt;
  230.     Nlm_FonT smallfnt = Nlm_GetFont( "Times", 9, false, false, false, "Roman");
  231.     //smallfnt= Nlm_programFont;
  232.  
  233.     nps.x= 1;
  234.     nps.y= 1; // clear some weird offset on new docs !? 
  235.     this->SetNextPosition( nps);
  236.     fStickpin= new DIconButton( cPushpin, this, &gPushpinOut);
  237.     this->NextSubviewToRight();
  238.  
  239. #if 0
  240.     this->GetNextPosition( &nps);
  241.     fParentPop= new DPopupList( cParentPopup, this);
  242.     fParentPop->Hide();
  243.     nps.x += 5;  
  244.     this->SetNextPosition( nps);
  245.     DGoDropMenuButton* ib = 
  246.         new DGoDropMenuButton( cParentDrop, this, &gDownTriangle, fParentPop);
  247.     this->NextSubviewToRight();
  248. #endif
  249.  
  250. #if 0
  251.     DIconButton* ib = new DIconButton( cParentDrop, this, &gDownTriangle);
  252.     this->NextSubviewToRight();
  253.     pr= new DPrompt( 0, this, "Recent:", 0, 0, smallfnt);             
  254.     //pr->SetResize( DView::fixed, DView::moveinsuper);
  255.     this->NextSubviewToRight();
  256.  
  257.     fParentPop= new DPopupList( cParentPopup, this);
  258.     //fParentPop->SetResize( DView::fixed, DView::moveinsuper);  
  259.     this->NextSubviewToRight();
  260.     this->GetNextPosition( &nps);
  261.     nps.x += 50; // 150 
  262.     this->SetNextPosition(nps);
  263. #endif
  264.  
  265.     pr= new DPrompt( 0, this, "Status:", 0, 0, smallfnt); 
  266.     //pr->SetResize( DView::fixed, DView::fixed);
  267.     this->NextSubviewToRight();
  268.  
  269.     fStatus= new DPrompt(  0, this, NULL, 150, 0, smallfnt);   // 350
  270.     //fStatus->SetResize( DView::fixed, DView::fixed);
  271.     this->NextSubviewBelowLeft();
  272.     if (fParent) fParent->fStatusLine= fStatus;
  273. }
  274.  
  275.  
  276. void DGopherListDoc::EmptyData(Boolean saveit)
  277. {
  278.     if (saveit)  
  279.         fParentlist->Push( fGolist);
  280.     else {
  281.         if (fOldlist) fOldlist->suicide(); //delete fOldlist;  
  282.         fOldlist= fGolist;
  283.         if (fParent) fParent->suicide();  
  284.         }
  285.     fGolist= NULL;
  286.     fParent= NULL;
  287.     //if (fGoview) fGoview->suicide();  //noooooooooo ... dview::deletesubviews...
  288.     if (fParentPop) {
  289.             //  doesn't vibrant know how to clean out a (popup)menu list !?
  290.         fParentPop->Reset(); // does this drop menu items ?? YES
  291.         //delete fParentPop;
  292.         //fParentPop= new DPopupList( cParentPopup, this);
  293.         }
  294.     if (fGoview) fGoview->SetEmptySelection(false);
  295.     fFirststuff= 1;
  296.     fInUse= false;
  297. }
  298.  
  299.  
  300. Boolean DGopherListDoc::ReplaceData( DGopher* parentGopher, char* name, DFile* aFile)
  301. {
  302.     if (!fInUse && !fPinned) {
  303.         Boolean ok = false;
  304.         if (parentGopher) ok= this->CanReadFrom( parentGopher);
  305.         else ok= this->CanReadFrom( aFile);
  306.         if (ok) {
  307.              EmptyData(true);    
  308.             if (name) this->SetTitle( name); 
  309.             if (parentGopher) {
  310.                 parentGopher->newOwner(); // DGopherListDoc constructor normally does this...
  311.                 this->Open( parentGopher);
  312.                 }
  313.             else this->Open( aFile);
  314.             return true;
  315.             }
  316.         return true; // !!!!!??? this is a funny result when we didn't replace !! but
  317.                 // it means don't try a new window !!
  318.         }
  319.     return false;
  320. }
  321.  
  322.  
  323. Boolean DGopherListDoc::ReplaceData( DGopherList* parentlist)
  324. {
  325.         // ! this is buggy still for real replace, but is also used for new DGoListDoc !
  326.     if (!fInUse && !fPinned && parentlist) {
  327.         EmptyData(false);
  328.         fGolist= parentlist;
  329.         fParent= fGolist->fParentMenu;
  330.         if (!fGoview) {
  331.             MakeSubviews(); //fGoview= new DGolistView(0, this, fGolist, kGolistViewWidth);
  332.             fGoview->ChangeRowSize( -1, fGolist->GetSize());  
  333.             }
  334.          else {
  335.              fGoview->fItems= fGolist;
  336.             short nold= fGoview->GetMaxRows();
  337.             short nnew= fGolist->GetSize();
  338.             fGoview->ChangeRowSize( -1, nnew-nold);  
  339.             }
  340.         fGoview->SetColWidths();     //!
  341.         this->Open(true);  
  342.         return true;
  343.         }
  344.     else
  345.         return false;
  346. }
  347.  
  348. Boolean DGopherListDoc::PopData( short numitems)
  349. {
  350.         // this freezes after first !!
  351.     short npop= MIN( numitems, fParentlist->GetSize());
  352.     if (!fInUse && !fPinned && npop) {
  353.     
  354.         EmptyData(false);
  355.         
  356.         for ( ; npop>0; npop--) {
  357.             if (fGolist) fGolist->suicide(); //delete fGolist;  
  358.             fGolist= (DGopherList*) fParentlist->Pop();
  359.             }
  360.  
  361.         if (!fGoview) {
  362.             MakeSubviews(); //fGoview= new DGolistView(0, this, fGolist, kGolistViewWidth);
  363.             fGoview->ChangeRowSize( -1, fGolist->GetSize());  
  364.             }
  365.          else {
  366.              fGoview->fItems= fGolist;
  367.             short nold= fGoview->GetMaxRows();
  368.             short nnew= fGolist->GetSize();
  369.             fGoview->ChangeRowSize( -1, nnew-nold);  
  370.             }
  371.         fGoview->SetColWidths();     //!
  372.                         
  373.         fParent= fGolist->fParentMenu;
  374.         this->Open(true);
  375.         return true;
  376.         }
  377.     else
  378.         return false;
  379. }
  380.  
  381.  
  382. Boolean DGopherListDoc::IsGopherDoc(DFile* aFile)
  383. {
  384.     // test to see if aFile is a gopher doc.
  385.     // this is a static function, usable w/o a DGopherListDoc object
  386.     
  387.     if (aFile && aFile->Exists()) {
  388.         char    line[256];
  389.         aFile->OpenFile();
  390.         aFile->ReadLine( line, 256);
  391.         return DGopherList::IsGopherLine( line);
  392.         }
  393.     else
  394.         return false;
  395. }
  396.  
  397.  
  398. void DGopherListDoc::SortView(DGopherList::Sorts sortorder)
  399. {
  400.     fGolist->SortList(sortorder);
  401.     fGoview->Invalidate();
  402. }
  403.  
  404. void DGopherListDoc::ToTextDoc( Boolean ViewAsLink)
  405. {
  406.     Nlm_ParData paratabs = {false, false, false, false, true, 0, 0}; // tabs==tabs
  407.   Nlm_ParData parafmt  = {false, false, false, false, false, 0, 0}; // tabs==colFmt
  408.     char    *txt     = NULL;
  409.     Nlm_ColData*    cols= NULL;
  410.     Nlm_ParData*    para= ¶tabs;
  411.  
  412.           // this colFmt needs work -- ?? use char sizes rather than pixel sizes ??
  413. #if 0  
  414. // DAMN SUN CC/CFRONT FAILS at THIS !? the bozo 
  415.     Nlm_ColData colFmt [8] = {
  416.       { 0, 0, 40, 1, gTextFont, 'l', FALSE, FALSE, FALSE, FALSE}, // name
  417.       { 0, 0,  7, 1, gTextFont, 'l', FALSE, FALSE, FALSE, FALSE},    // date
  418.       { 0, 0,  6, 1, gTextFont, 'l', FALSE, FALSE, FALSE, FALSE},    // size
  419.       { 0, 0, 10, 1, gTextFont, 'l', FALSE, FALSE, FALSE, FALSE},    // kind
  420.       { 0, 0, 25, 1, gTextFont, 'l', FALSE, FALSE, FALSE, FALSE},    // path
  421.       { 0, 0, 25, 1, gTextFont, 'l', FALSE, FALSE, FALSE, FALSE},    // host
  422.       { 0, 0,  5, 1, gTextFont, 'r', FALSE, FALSE, FALSE, FALSE},    // port
  423.       { 0, 0, 30, 1, gTextFont, 'l', FALSE, FALSE, FALSE, TRUE}        // admin
  424.         };
  425. #else
  426. // for damn sun CC cfront
  427.         Nlm_ColData colFmt [8];
  428.        Nlm_ColData colFmt0 ={ 0, 0, 40, 1, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE}; // name
  429.        Nlm_ColData colFmt1 ={ 0, 0,  7, 1, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE};    // date
  430.        Nlm_ColData colFmt2 ={ 0, 0,  6, 1, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE};    // size
  431.        Nlm_ColData colFmt3 ={ 0, 0, 10, 1, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE};    // kind
  432.        Nlm_ColData colFmt4 ={ 0, 0, 25, 1, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE};    // path
  433.        Nlm_ColData colFmt5 ={ 0, 0, 25, 1, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE};    // host
  434.        Nlm_ColData colFmt6 ={ 0, 0,  5, 1, NULL, 'r', FALSE, FALSE, FALSE, FALSE, FALSE};    // port
  435.        Nlm_ColData colFmt7 ={ 0, 0, 30, 1, NULL, 'l', FALSE, FALSE, FALSE, FALSE, TRUE};        // admin
  436.     colFmt[0]= colFmt0;
  437.         colFmt[1]= colFmt1;
  438.         colFmt[2]= colFmt2;
  439.         colFmt[3]= colFmt3;
  440.         colFmt[4]= colFmt3;
  441.         colFmt[5]= colFmt5;
  442.         colFmt[6]= colFmt6;
  443.         colFmt[7]= colFmt7;
  444. #endif
  445.     
  446.     if (ViewAsLink)
  447.         txt= fGolist->WriteLinksForServer();
  448.     else {
  449.             //! later -- set these from user display prefs ....
  450.         Boolean showdate= true, showsize= true, showkind= true, showpath= false,
  451.                 showhost=true, showport=true, showadmin= true;
  452.         txt= fGolist->WriteLinksForDisplay( showdate, showsize, showkind, showpath,
  453.                         showhost, showport, showadmin);
  454.                         
  455.             // this col formatting isn't working right -- name col is too short
  456.         //cols= colFmt;
  457.         //para= ¶fmt;
  458.         }
  459.         
  460.     if (txt) {
  461.         // ?? add fancy col tabs ForDisplay ??
  462.         char name[256];
  463.         strcpy(name,"Text of ");
  464.         long len= strlen(name);
  465.         char *namep= name+ len;
  466.         len = 256 - len;
  467.         (void) this->GetTitle(namep, len);
  468.         DWindow* aWin= new DWindow( 0, gApplication, document, -1, -1, -10, -10, name);
  469.         DTextDocPanel* aDoc= new DTextDocPanel( 0, aWin, 500, 300);
  470.         aDoc->SetResize( DView::matchsuper, DView::relsuper);
  471.         //aDoc->SetSlateBorder( false);
  472.         aDoc->SetTabs( gTextTabStops);
  473.         aDoc->Append( txt, para, cols, gTextFont);
  474.         aWin->Open();  
  475.         aDoc->SizeToSuperview( aWin, true, false);
  476.         }
  477. }
  478.  
  479.  
  480. void DGopherListDoc::ShowMessage(const char* msg)
  481. {
  482.     if (fStatus) fStatus->SetTitle( (char*)msg);
  483. }
  484.  
  485.  
  486. // static
  487. void DGopherListDoc::ProcessFile( DFile* aFile)
  488. {
  489.     Boolean replaced= false;
  490.     //if (gGopherDoc) // !??? this is bad, set to non-null when must be null, on 68Kmac
  491.     //    replaced= gGopherDoc->ReplaceData( NULL, NULL, aFile);
  492.     if (! replaced ) {
  493.         DGopherListDoc* adoc= new DGopherListDoc( kGoListdoc);
  494.         adoc->Open(aFile);   
  495.         }
  496. }
  497.  
  498.  
  499.  
  500. // static
  501. Boolean DGopherListDoc::ProcessGopherWithTest( DGopher* theGo)
  502. {
  503.     DWindow* win;
  504.     
  505.         // ?? always reset thread state here ??
  506.     theGo->fThreadState= DGopher::kThreadNotStarted;  
  507.     if (theGo->fThreadState == DGopher::kThreadNotStarted) {
  508.         if (theGo->fHasAsk && theGo->fHaveReply) theGo->fQueryPlus= theGo->fReplyData;  
  509.         theGo->OpenQuery();
  510.         }
  511.     //fInUse= true; //??
  512.     
  513.     if (theGo->fThreadState == DGopher::kThreadDoneReading) { 
  514.         theGo->fThreadState= DGopher::kThreadNotStarted; // ! need to reset this somewhere for used gophers
  515.         return false; 
  516.         }
  517.     else {
  518.         DTask* readTask= theGo->newTask(cRead, DGopher::kGopherTask);
  519.         readTask->SetRepeat(true);
  520.         theGo->fTransferType= kTransferBinary;  // ! NOT True always, but need in cases of binary data? ?!
  521.         theGo->ProcessTask(readTask); // read 1st part of data
  522.         theGo->PostTask( readTask);        // post to event handler to read rest of data
  523.         
  524.         char * cbeg = theGo->fInfo;
  525.         ulong clen = theGo->fInfoSize;
  526.         char * datastart;
  527.         short format= DGoLinkedTextDoc::TestFormat(cbeg, clen, datastart);
  528.         switch (format) {
  529.         
  530.             case DGopher::cGopherNetDoc:
  531.                 DGopherListDoc::NewNetdoc( theGo, readTask);
  532.                 break;
  533.  
  534.             case DGopher::cNewGopherFolder:
  535.             case DGopher::cOpenGopherFolder:
  536.                 if (true) { // (! this->ReplaceData( theGo, NULL, NULL)) {
  537.                     DGopherListDoc* win= new DGopherListDoc( DGopherListDoc::kGoListdoc, theGo);
  538.                     win->Open( theGo);  
  539.                     }
  540.                 break;
  541.         
  542.             case DGopher::cNewGopherFile:
  543.             case DGopher::cOpenGopherFile:
  544.             caseFile:
  545.                 win= new DGopherFileDoc( DGopherFileDoc::kGoFiledoc, theGo);  
  546.                 win->Open();
  547.                 break;
  548.     
  549. #if 0
  550.             case DHTMLHandler::kHTMLformat: 
  551.             case DGIFHandler::kGIFformat    : 
  552.             case DPICTHandler::kPICTformat:  
  553.             case DRTFHandler::kRTFformat  : 
  554. #endif
  555.             default:
  556.                 if (theGo->fSaveToDisk) goto caseFile;
  557.                 if (gGopherTextDoc && gGopherTextDoc->PushNewDoc(theGo, NULL)) 
  558.                     ;
  559.                 else {
  560.                     win= new DGoLinkedTextDoc( DGoLinkedTextDoc::kGoLitextdoc, theGo, NULL); //?? this);  
  561.                     win->Open();
  562.                     }
  563.                 break;
  564.  
  565.                 }
  566.             return true;
  567.             }
  568. }
  569.  
  570.  
  571.  
  572. // static
  573. void DGopherListDoc::NewNetdoc( DGopher* theGo, DTask* readTask)
  574. {
  575.     DWindow* win;
  576.     Boolean  doPostReader = false;
  577.     
  578.     // document is gopher link data followed by any other document data kind
  579. #if 1
  580.     DGopherList* newGolist= new DGopherList(NULL);
  581. #else
  582.     DGopherListDoc* newGopherDoc= new DGopherListDoc();
  583.     newGopherDoc->fGolist= new DGopherList(NULL);
  584.     newGopherDoc->fGoview= new DGolistView(0, newGopherDoc, newGopherDoc->fGolist, kGolistViewWidth);
  585. #endif
  586.  
  587.     // read data from net & process as gopherdoc data as long as it
  588.     // is right kind: +INFO: ... +etc:
  589.     // ?? look for transition flag, +DATA: ??
  590.     if (theGo->fThreadState == DGopher::kThreadNotStarted) {
  591.         if (theGo->fHasAsk && theGo->fHaveReply) theGo->fQueryPlus= theGo->fReplyData;  
  592.         theGo->OpenQuery();
  593.         }
  594.     theGo->fTransferType= kTransferBinary; // !?! this is a problem !! need to resolve
  595.  
  596.     if (theGo->fInfoSize<10 && theGo->fThreadState == DGopher::kThreadDoneReading) { 
  597.         theGo->fThreadState= DGopher::kThreadNotStarted; // ! need to reset this somewhere for used gophers
  598.         return; 
  599.         }
  600.     else {
  601.         char * cbeg, * cdata, * cp, * ep;
  602.         ulong clen;
  603.         Nlm_Uint4 ioffs;
  604.         Boolean found= false;
  605.         ioffs= 0;
  606.         cdata= NULL;
  607.         if (readTask) {
  608.             doPostReader= false;
  609.             }
  610.         else {
  611.             readTask= theGo->newTask(cRead, DGopher::kGopherTask);
  612.             readTask->SetRepeat(true);
  613.             doPostReader= true;
  614.             }
  615.         do {
  616.             theGo->ProcessTask(readTask); // read 1st part of data
  617.             cbeg = theGo->fInfo;
  618.             clen = theGo->fInfoSize;
  619.             cp= cbeg + ioffs;
  620.             found= false;
  621.             do {
  622.               ep= (char*) MemChr( cp, kLF, clen - ioffs);
  623.               if (!ep) ep= (char*) MemChr( cp, kCR, clen - ioffs);
  624.               if (ep) {
  625.                   cp = ep+1;
  626.                   if (*cp == '+') found = (StrNICmp( cp, "+DATA:", 6) == 0);
  627.                   }
  628.               ioffs= cp - cbeg;
  629.             } while (!found && ep);
  630.             if (found) cdata= cp;
  631.         } while (!found && theGo->fThreadState != DGopher::kThreadDoneReading);
  632.             
  633.          if (found) {
  634.              
  635.              {  // drop the +MENU: indent !
  636.              char *cp, *newp, thisc, lastc;
  637.              ioffs= 0;
  638.             found= Nlm_StrngPos(cbeg, "+MENU:"/*CRLF*/,0, false/*case*/, &ioffs);
  639.             if (found) {
  640.                 cbeg += ioffs + 6; 
  641.                 for (cp= newp= cbeg, lastc= 0; cp < cdata && *cp; cp++) {
  642.                     thisc= *cp;
  643.                     if (!(thisc == ' ' && (lastc == kCR || lastc == kLF))) 
  644.                         *newp++= thisc;
  645.                     lastc= thisc;
  646.                     }
  647.                 *newp= 0;
  648.                 }
  649.             }
  650.             
  651.           //newGopherDoc->AddData( cbeg, cdata-cbeg); //ReadLinks
  652.           newGolist->ReadLinks(  cbeg, cdata-cbeg);
  653.           cdata += 6; // ?? + sizeof("+DATA:"/*CRLF*/);
  654.           while (*cdata == '+' || isspace(*cdata)) cdata++;
  655.             // look for gopher size info
  656.             if (*cdata == '-' || isdigit(*cdata)) {
  657.                 theGo->fBytesExpected = atol( cdata);
  658.               while (*cdata == '-' || isdigit(*cdata)) cdata++;
  659.             if (*cdata == kCR || *cdata == kLF ) cdata++;
  660.             if (*cdata == kCR || *cdata == kLF ) cdata++;
  661.                 }
  662.             theGo->fInfoSize -= (cdata - theGo->fInfo);
  663.             Nlm_MemMove( theGo->fInfo, cdata, theGo->fInfoSize+1); 
  664.             }
  665.             
  666.         //if (theGo->fInfoSize < 1024) 
  667.         if (theGo->fThreadState != DGopher::kThreadDoneReading)
  668.             theGo->ProcessTask(readTask); // read more of data so testor can find format
  669.         if (doPostReader) theGo->PostTask(readTask);        // post to event handler to read rest of data
  670.         if (gGopherTextDoc && gGopherTextDoc->PushNewDoc(theGo, newGolist)) 
  671.             ;
  672.         else {
  673.             win= new DGoLinkedTextDoc( DGoLinkedTextDoc::kGoLitextdoc, theGo, newGolist); //?? this);  
  674.             win->Open();
  675.             }
  676.         //newGopherDoc->suicide(); //!? DGoLinkedTextDoc is now owner
  677.         newGolist->suicide(); 
  678.         }
  679. }
  680.  
  681.  
  682. //static
  683. void DGopherListDoc::ProcessGopher( DGopher* theGo, short itsViewChoice)
  684. {
  685.     DWindow* win;
  686.     
  687.     if (theGo) {
  688.         gCursor->watch();
  689.  
  690.         switch (theGo->ItemForm(itsViewChoice)) {   
  691.  
  692. #if 1
  693.             case DGopher::cOpenGopherText:
  694.             case DGopher::cNewGopherText:
  695.             case DGopher::cNewGopherFolder:
  696.             case DGopher::cOpenGopherFolder:
  697.             caseText:
  698.                 (void) DGopherListDoc::ProcessGopherWithTest( theGo);                
  699.                 break;
  700. #else
  701.             case DGopher::cOpenGopherText:
  702.             case DGopher::cNewGopherText:
  703.             caseText:
  704.                 if (theGo->fSaveToDisk) goto caseFile;
  705.                 if (gGopherTextDoc && gGopherTextDoc->PushNewDoc(theGo, NULL)) 
  706.                     ;
  707.                 else
  708.                     win= new DGoLinkedTextDoc( DGoLinkedTextDoc::kGoLitextdoc, theGo, NULL); //?? this);  
  709.                     win->Open();
  710.                     }
  711.                 break;
  712.  
  713.             case DGopher::cNewGopherFolder:
  714.             case DGopher::cOpenGopherFolder:
  715.                 if (! this->ReplaceData( theGo, NULL, NULL)) {
  716.                     DGopherListDoc* win=
  717.                         new DGopherListDoc( DGopherListDoc::kGoListdoc, theGo);
  718.                     win->Open( theGo);  
  719.                     }
  720.                 break;
  721. #endif    
  722.  
  723.             case DGopher::cGopherNetDoc:
  724.                 DGopherListDoc::NewNetdoc( theGo, NULL);
  725.                 break;
  726.  
  727.             case DGopher::cNewGopherImage:
  728.             case DGopher::cOpenGopherImage:
  729.                 {
  730.                 DGopherMap* aMapper= NULL;
  731.                 if (gGopherMap) aMapper = gGopherMap->MatchHandlerKind( theGo);
  732.                 if (aMapper && aMapper->GetDisplay() ) goto caseText;
  733.                 else goto caseFile;
  734.                 }
  735.                 break;
  736.                                 
  737.             case DGopher::cNewGopherFile:
  738.             case DGopher::cOpenGopherFile:
  739.             caseFile:
  740.                 win= new DGopherFileDoc( DGopherFileDoc::kGoFiledoc, theGo); //'GFil'
  741.                 win->Open();
  742.                 break;
  743.         
  744.             case DGopher::kGopherTask:
  745.                 if (theGo->fHasAsk && theGo->fHaveReply) theGo->fQueryPlus= theGo->fReplyData;  
  746.                 theGo->OpenQuery();
  747.                 break;
  748.  
  749.             case DGopher::cGopherGetInfo:
  750.                 win= new DGopherInfoDoc( DGopherInfoDoc::kGoInfodoc, theGo); // 'GIfo'
  751.                 win->Open();
  752.                 break;
  753.             
  754.             case DGopher::cNewGopherAsk:
  755.             case DGopher::cOpenGopherAsk:
  756.                 win= 
  757.                     new DGopherAskDoc( DGopherAskDoc::kGoAskdoc, theGo, gGopherDoc/*this*/, itsViewChoice);
  758.                 if (win) win->Open();
  759.                 break;
  760.     
  761.             default:
  762.                 break;
  763.             }
  764.         
  765.         gCursor->arrow();
  766.         }
  767. }
  768.  
  769.  
  770. // static
  771. void DGopherListDoc::ReadItemInfo(DGopher* theGo)
  772. {
  773.     if (theGo) {
  774.         gCursor->watch();
  775.         short aSavedType= theGo->fTransferType;
  776.         theGo->fTransferType= kTransferText;
  777.         theGo->InfoTask();   
  778.         theGo->ShowMessage("read item info...");
  779.         while (theGo->ThreadProgress() != DGopher::kThreadDoneReading) {
  780.             gApplication->ProcessTasks();  // wait for info to arrive
  781.             }
  782.         theGo->CloseQuery(); // patch for mswin net bug ?? 
  783.         theGo->DeleteInfo(); 
  784.         theGo->ShowMessage(" ");
  785.         theGo->fTransferType= aSavedType;
  786.         gCursor->arrow();
  787.         }
  788. }
  789.  
  790. void DGopherListDoc::TopOfGopherHole()
  791. {    
  792.     DGopher* aGopher= fGoview->SelectedGopher();
  793.     short aRow = fGoview->GetSelectedRow();
  794.     if (aGopher) {
  795.         DGopher* bGopher= DGopherList::CopyToNewKind( kTypeFolder, aGopher, fGolist);
  796.         if (bGopher) {
  797.             bGopher->StorePath("");         // this is key to top of gopher server
  798.             char buf[256];
  799.             StrCpy(buf, "Gopher at ");
  800.             StrNCat(buf, bGopher->GetHost(), 255);
  801.             bGopher->StoreName(buf);          
  802.             fGolist->InsertBefore( aRow, (DObject*) bGopher);
  803.             fGoview->ChangeRowSize( aRow, 1); 
  804.             Dirty(); 
  805.             }
  806.         }
  807. }
  808.  
  809. void DGopherListDoc::EditOldGopher()
  810. {    
  811.     short aRow = fGoview->GetSelectedRow();
  812.     DGopher *aGopher= fGoview->SelectedGopher();
  813.     if (aGopher) {
  814.         char oldKind= aGopher->fType;
  815.         if (aGopher->Edit(true) ) {
  816.             if (aGopher->fType != oldKind) {
  817.               DGopher* bGopher=
  818.                    DGopherList::CopyToNewKind( aGopher->fType, aGopher, fGolist, true);
  819.               if (bGopher) {
  820.                     delete aGopher; //aGopher->suicide();  
  821.                     fGolist->AtPut( aRow, (DObject*) bGopher); //! re-insert bgopher into list 
  822.                     }
  823.                 }
  824.             Nlm_RecT vbounds;
  825.             fGoview->GetRowRect( aRow, vbounds);
  826.             fGoview->InvalRect( vbounds);
  827.             Dirty(); 
  828.             }
  829.         }
  830. }
  831.  
  832.  
  833. void DGopherListDoc::InsertNewGopher(Boolean editAll)
  834. {            
  835.     short aRow = fGoview->GetSelectedRow();
  836.     if (aRow==0) aRow= fGolist->GetSize();
  837.     aRow++;    // insert after...
  838.     
  839.     DGopher* aGopher= new DGopher(); 
  840.     char oldKind= aGopher->fType;    
  841.     aGopher->SetOwner(fGolist); 
  842.     if (!editAll) aGopher->fType= kTypeFolder; // !editAll is used for NewServer() call !
  843.      
  844.     if (aGopher->Edit( editAll)) {
  845.         //if (aGopher->fType != oldKind || !editAll) // bug here -- missing CopyToNewKind
  846.         {
  847.          DGopher* bGopher=
  848.               DGopherList::CopyToNewKind( aGopher->fType, aGopher, fGolist, true); 
  849.          if (bGopher) {
  850.                 delete aGopher; //aGopher->suicide();  
  851.                 aGopher= bGopher;
  852.                 }
  853.             }
  854.             
  855.         fGolist->InsertBefore( aRow, (DObject*) aGopher);
  856.         fGoview->ChangeRowSize( aRow, 1);  
  857.         Dirty(); // !? this needs to track the fGolist, which can be popped/pushed
  858.         }        
  859.     else
  860.         delete aGopher; //aGopher->suicide();   
  861.     
  862.  
  863. // static
  864. short DGopherListDoc::DefaultGopherView(DGopher* aGopher)
  865. {
  866.     Boolean canDisplay = false;
  867.     short bestItem = 0;
  868.     DGopherMap* aMapper;
  869.     
  870.     if (!aGopher) return 0;
  871.     
  872.             // ???
  873.     if (aGopher->fType == kTypeFolder 
  874.         || aGopher->fType == kTypeQuery
  875.         || aGopher->fIsMap ) 
  876.             return 0;
  877.             
  878.     gCursor->watch();
  879.     if (aGopher->fIsPlus == kGopherPlusYes && !aGopher->fViews) 
  880.         DGopherListDoc::ReadItemInfo(aGopher);
  881.     if (aGopher->fViews) {
  882.  
  883. #if 0
  884.         aGopher->CheckViewMappers();
  885.         // ?? now how do we get bestItem value ?? set aGopher->fViewChoice ??
  886.         
  887. #else
  888.         char *cp, *viewkind;
  889.         short i, nviews;
  890.         unsigned short lastrank, bestPref = 0;
  891.         
  892.         nviews= aGopher->fViews->GetSize();
  893.         for (i= 0; i<nviews; i++) {
  894.             lastrank = 0; 
  895.             DGopherItemView* giv= (DGopherItemView*) aGopher->fViews->At(i);
  896.             viewkind= (char*)giv->Kind();
  897.             aMapper= gGopherMap->MatchHandlerKind( lastrank, viewkind); 
  898.             if (aMapper) {
  899.                 if ( aMapper->GetDisplay() ) canDisplay= true;
  900.                 if ( aMapper->fPreference > bestPref) {
  901.                     bestItem= i + 1;
  902.                     bestPref= aMapper->fPreference;
  903.                     }
  904.                 }
  905.             }
  906. #endif
  907.  
  908.         }
  909.     else {
  910.         aMapper= gGopherMap->MatchGopherType( aGopher->fType, true); 
  911.         if (aMapper) {
  912.             if ( aMapper->GetDisplay() ) canDisplay= true;
  913.             //if (aMapper->fHandlerType == 1) canDisplay= true;
  914.             //else if (aMapper->fHandlerType == 2) canFile= true;
  915.             }
  916.         }
  917.         
  918.     //gCursor->arrow();
  919.     return bestItem;
  920. }
  921.  
  922.  
  923.  
  924.  
  925.  
  926.  
  927.  
  928.  
  929.  
  930.  
  931. class DGoviewListView;
  932.  
  933. class DViewChoiceDialog : public DWindow 
  934. {
  935. public:
  936.     enum ViewChoiceCmds { cFetchToDisplay = 111, cFetchToFile, cFetchInfo, 
  937.                                         cFetchGroup, cFetchEdit, cMapBut };
  938.     DGoviewListView*    fListBox;  //DListBox * fListBox;
  939.     short             fViewChoice, fFetchMethod;
  940.     DGopher  * fParentGo;
  941.     DCluster * fFetchCluster;
  942.     
  943.     DViewChoiceDialog(DGopher* itsGopher);
  944.     virtual void Open();
  945.     virtual void OkayAction();
  946.     virtual short Result() { return fViewChoice; }
  947.     virtual Boolean IsMyAction(DTaskMaster* action);
  948. };
  949.  
  950.  
  951. class DGoviewListView : public DTableView 
  952. {
  953. public:
  954.     DViewChoiceDialog *    fDialog;
  955.     DList * fItems; // of DGopherItemView*
  956.     DGopher * fGopher;
  957.     Nlm_FonT    fItalFont;
  958.     
  959.     DGoviewListView(long id, DGopher* itsGopher, DViewChoiceDialog* itsDialog, short pixwidth, short pixheight);
  960.     virtual void DoClickAt(short row, short col);
  961.     virtual void SingleClickAt(short row, short col);
  962.     virtual void DoubleClickAt(short row, short col);
  963.     virtual void GetReadyToShow();
  964.     virtual void DrawCell(Nlm_RecT r, short row, short col);
  965.     virtual DGopherItemView* SelectedView();
  966.     virtual void  SetValue( short value) { SelectCells( value, 0, false); }
  967.     virtual short GetValue() { 
  968.         if (GetSelectedRow() != kNoSelection) return (1+GetSelectedRow());
  969.         else return 0;
  970.       }
  971. };
  972.  
  973.  
  974. DGoviewListView::DGoviewListView(long id, DGopher* itsGopher, DViewChoiceDialog* itsDialog, 
  975.                                                 short pixwidth, short pixheight):
  976.     DTableView( id, itsDialog, pixwidth, pixheight, 5, 2, 50, 15, true, false),
  977.     fGopher( itsGopher), fItalFont(NULL),
  978.     fDialog(itsDialog)
  979. {    
  980.     fItems= fGopher->fViews;
  981.     this->SetSlateBorder(true); 
  982.     this->SetResize( DView::relsuper, DView::relsuper);
  983.     this->SetTableFont(gGoviewFont);
  984.     if (gGoviewFontName && *gGoviewFontName)
  985.         fItalFont= Nlm_GetFont( gGoviewFontName, gGoviewFontSize, false, true, false, NULL);
  986.     else
  987.         fItalFont= Nlm_GetFont( gTextFontName, gTextFontSize, false, true, false, NULL);
  988.     this->GetReadyToShow(); // ??
  989. }
  990.  
  991. void DGoviewListView::DoClickAt( short row, short col)
  992. {
  993.     DGopherItemView* giv= (DGopherItemView*) fItems->At(row);
  994.     if (giv) {
  995.         if (giv->fViewStatus  == DGopherItemView::kUnknownStatus) {
  996.             // dialog to append view handler
  997.             if (DGopherMapDoc::EditHandler( (char*) giv->Kind())) {
  998.                 fGopher->CheckViewMappers();
  999.                 this->Invalidate();
  1000.                 }
  1001.             }
  1002.         else {
  1003.             DTaskMaster okay(cOKAY);
  1004.             fDialog->IsMyAction( &okay);
  1005.             //fDialog->OkayAction();
  1006.             //fDialog->Close();
  1007.             }
  1008.         }
  1009. }
  1010.  
  1011. void DGoviewListView::SingleClickAt( short row, short col)
  1012. {
  1013.     DTableView::SingleClickAt( row, col); // must select item !
  1014.     if (gSingleClicker) DoClickAt( row, col);
  1015. }
  1016.  
  1017. void DGoviewListView::DoubleClickAt( short row, short col)
  1018. {
  1019.     DTableView::DoubleClickAt( row, col); 
  1020.     if (gDoubleClicker) DoClickAt( row, col);
  1021. }
  1022.  
  1023.  
  1024. DGopherItemView* DGoviewListView::SelectedView()
  1025. {
  1026.     if (GetSelectedRow() != kNoSelection) 
  1027.         return (DGopherItemView*)fItems->At( GetSelectedRow());
  1028.     else 
  1029.         return NULL;
  1030. }
  1031.  
  1032. void DGoviewListView::GetReadyToShow()
  1033. {
  1034.     short  wid;
  1035.     SelectFont();
  1036.     short charheight= Nlm_FontHeight();
  1037.     if (fItems && fItems->GetSize() > 0) SetTableSize( fItems->GetSize(), GetMaxCols());
  1038.     SetItemHeight(0, GetMaxRows(), charheight);
  1039.     wid= Nlm_StringWidth("* ");
  1040.     this->SetItemWidth( 0, 1, wid);
  1041.     wid= Nlm_StringWidth("application/gopher+-menu-long");
  1042.     this->SetItemWidth( 1, 1, wid);  
  1043. }
  1044.  
  1045. void DGoviewListView::DrawCell(Nlm_RecT r, short row, short col)
  1046. {
  1047.     if (col) r.left += 2; // quick fix for cells against each
  1048.     DGopherItemView* giv= (DGopherItemView*) fItems->At(row);
  1049.     if (giv) {
  1050.         Boolean changefont= false;
  1051.         //if (giv->fViewStatus == DGopherItemView::kMaxStatus) 
  1052.         //    this->SetValue( row);          
  1053.         switch (col) {
  1054.             case 0:  
  1055.                 Nlm_DrawString(&r, (char*) giv->ViewStatus(), 'l', false);
  1056.                 break;   
  1057.             case 1: 
  1058.                 if (giv->fViewStatus==DGopherItemView::kUnknownStatus && fItalFont) {
  1059.                     changefont= true;
  1060.                      Nlm_SelectFont(fItalFont);
  1061.                      }
  1062.                 Nlm_DrawString(&r, (char*) giv->ViewVal(), 'l', false);
  1063.                 break;   
  1064.             }
  1065.         if (changefont) SelectFont();
  1066.         }
  1067. }
  1068.  
  1069.  
  1070.  
  1071.  
  1072.  
  1073.  
  1074.  
  1075.  
  1076. DViewChoiceDialog::DViewChoiceDialog(DGopher* itsGopher) :
  1077.         DWindow( 0, NULL, DWindow::fixed, -10, -10, -50, -20, "View choices", kDontFreeOnClose),
  1078.         fViewChoice(0),
  1079.         fFetchMethod(0),
  1080.         fParentGo(itsGopher),
  1081.         fListBox(NULL)
  1082. {    
  1083. }
  1084.  
  1085. Boolean DViewChoiceDialog::IsMyAction(DTaskMaster* action) 
  1086. {
  1087.       switch (action->Id()) {
  1088.  
  1089.         default:
  1090.             return DWindow::IsMyAction(action);    
  1091.             
  1092. #if 0            
  1093.             case cMapBut: {
  1094.                 short nviews= 0;
  1095.                 if (fParentGo && fParentGo->fViews) 
  1096.                     nviews= fParentGo->fViews->GetSize();
  1097.                 if (nviews) {        
  1098.                     long i;
  1099.                     char* cp;
  1100.                     for (i= 0; i<nviews; i++) {
  1101.                         char * viewkind;
  1102.                         unsigned short lastrank = 0; 
  1103.                         DGopherItemView* giv= (DGopherItemView*) fParentGo->fViews->At(i);
  1104.                         viewkind= (char*)giv->Kind();
  1105.                         DGopherMap* aMapper= gGopherMap->MatchHandlerKind( lastrank, viewkind); 
  1106.                         if (!aMapper) {
  1107.                             
  1108.                             }
  1109.                         }
  1110.                     }
  1111.                 }
  1112.                 return true;
  1113. #endif
  1114.  
  1115.         }
  1116. }
  1117.  
  1118.  
  1119. void DViewChoiceDialog::OkayAction() 
  1120.     if (fListBox) fViewChoice= fListBox->GetValue(); /* - 1;  */
  1121.     else fViewChoice= 0;
  1122.     if (fFetchCluster) switch ( fFetchCluster->GetValue()) {
  1123.         default:
  1124.         case 1: fFetchMethod= cFetchToDisplay; break;
  1125.         case 2: fFetchMethod= cFetchToFile; break;
  1126.         case 3: fFetchMethod= cFetchInfo; break;
  1127.         case 4: fFetchMethod= cFetchEdit; break;
  1128.         }
  1129. }
  1130.  
  1131. void DViewChoiceDialog::Open()
  1132. {
  1133.     DCluster* clu;
  1134.     DRadioButton* rb;
  1135.     DView* super = this;
  1136.     DPrompt* pr;
  1137.     unsigned short lastrank, bestPref = 0;
  1138.     long  nviews = 0, bestItem = 0;
  1139.     long    macType, macSire;
  1140.     char * viewkind = NULL;
  1141.     DGopherMap* aMapper;
  1142.     Boolean canDisplay= false, canFile= true; // always?? even for folder?
  1143.     Boolean unmapped= false;
  1144.     char namebuf[256];
  1145.     
  1146.     sprintf( namebuf, "Fetching '%s'", (char*)fParentGo->ShortName());
  1147.     pr= new DPrompt(0, this, namebuf, 0, 0, Nlm_programFont);         
  1148.     this->NextSubviewBelowLeft();
  1149.     sprintf( namebuf,  "Mod-date: %s   Size: %s", (char*)fParentGo->GetDate(), (char*)fParentGo->GetDataSize());
  1150.     pr= new DPrompt(0, this, namebuf, 0, 0, Nlm_programFont);         
  1151.     this->NextSubviewBelowLeft();
  1152.     
  1153.     if (fParentGo && fParentGo->fViews) {
  1154.         fParentGo->CheckViewMappers();
  1155.         short height= 12 * Max( 3, Min( 7, fParentGo->fViews->GetSize()));
  1156.         fListBox= new DGoviewListView( 0, fParentGo, this, 250, height);
  1157.         fListBox->SetResize( DView::relsuper, DView::relsuper);
  1158.         fListBox->SetValue( fParentGo->fViewchoice - 1); 
  1159.         lastrank = 0; 
  1160.         aMapper= gGopherMap->MatchHandlerKind( lastrank, 
  1161.                                     (char*)fParentGo->GetViewChoiceKind()); 
  1162.         if (aMapper && aMapper->GetDisplay() ) canDisplay= true;
  1163.         
  1164.         this->NextSubviewBelowLeft();
  1165.         sprintf( namebuf, " ? is an unknown view, double-click to link to a handler"LINEEND" * indicates the best view");
  1166.         //new DPrompt(0, this, namebuf, 0, 0, gSmallFont);         
  1167.         new DNotePanel(0, this, namebuf, 250, 0, gSmallFont);
  1168.         //this->NextSubviewBelowLeft();
  1169.         }
  1170.      
  1171.     else {
  1172.         // no views
  1173.         fListBox= NULL;
  1174.         pr= new DPrompt(0, this, "No view data. Default view is selected.", 0, 0, Nlm_programFont);         
  1175.         aMapper= gGopherMap->MatchGopherType( fParentGo->fType, true); 
  1176.         if (aMapper && aMapper->GetDisplay() ) canDisplay= true;
  1177.         }
  1178.  
  1179.         
  1180.     clu= new DCluster(cFetchGroup, super, 15, 5, false, "Fetch options");
  1181.     fFetchCluster= clu;
  1182.     super= clu;
  1183.     rb= new DRadioButton( cFetchToDisplay, super, "to Display");
  1184.     if (!canDisplay) rb->Disable();
  1185.     else rb->SetStatus(true); // ?? or clu->SetValue(1); 
  1186.  
  1187.     super->NextSubviewToRight();
  1188.     rb= new DRadioButton( cFetchToFile, super, "to File");
  1189.     if (!canFile) rb->Disable();
  1190.     else if (!canDisplay) rb->SetStatus(true);
  1191.     
  1192.     super->NextSubviewToRight();
  1193.     rb= new DRadioButton( cFetchInfo, super, "Get Info");
  1194.  
  1195. #ifdef BYVIEW_EDIT
  1196.     super->NextSubviewToRight();
  1197.     rb= new DRadioButton( cFetchEdit, super, "Edit");
  1198. #endif
  1199.     super= this;
  1200.     
  1201.     //if (unmapped) DButton* but= new DButton( cMapBut, super, "Map unknown(?) types");
  1202.      
  1203.     this->AddOkayCancelButtons();    
  1204.     gCursor->arrow();
  1205.     DWindow::Open();
  1206. }
  1207.  
  1208.  
  1209.  
  1210.  
  1211.     
  1212. // static
  1213. Boolean DGopherListDoc::GopherByViewDialog(DGopher* go, DGopherList* itsList) 
  1214. {
  1215.     short iview= 0;
  1216.     Boolean result= false;
  1217.     if (go) { 
  1218.         if (go->fIsPlus == kGopherPlusYes && !go->fViews) 
  1219.             DGopherListDoc::ReadItemInfo(go);
  1220.         DViewChoiceDialog* dlg= new DViewChoiceDialog(go);
  1221.         if ( dlg->PoseModally() ) {
  1222.             iview = dlg->Result();
  1223.             Boolean oldsave= go->fSaveToDisk;
  1224.             switch (dlg->fFetchMethod) {
  1225.                 default:
  1226.                 case DViewChoiceDialog::cFetchToDisplay: go->fSaveToDisk= false; break;
  1227.                 case DViewChoiceDialog::cFetchToFile: go->fSaveToDisk= true; break;
  1228.                 case DViewChoiceDialog::cFetchInfo  : iview= DGopher::kGetItemInfo; break;
  1229.  
  1230. #ifdef BYVIEW_EDIT
  1231.                         // this is mainly for debugging golinkdocs ...
  1232.                 case DViewChoiceDialog::cFetchEdit  : 
  1233.                 {    
  1234.                 char oldKind= go->fType;
  1235.                 if (go->Edit(true) ) {
  1236.                     if (go->fType != oldKind) {
  1237.                             // ?? use go->fOwnerList instead of passing itsList ??
  1238.                       DGopher* bGopher= 
  1239.                           DGopherList::CopyToNewKind( go->fType, go, itsList, true);
  1240.                       if (bGopher) {
  1241.                             long aRow= itsList->GetIdentityItemNo((DObject*) go);        // uses long(item) == long(indexobj)
  1242.                             itsList->AtPut( aRow, (DObject*) bGopher); //! re-insert bgopher into list 
  1243.                             delete go; //go->suicide();  
  1244.                             }
  1245.                         }
  1246.                     }
  1247.                 delete dlg;
  1248.                 return true;
  1249.                 }
  1250.                 break;
  1251. #endif
  1252.  
  1253.                 }
  1254.             delete dlg;
  1255.             result= true;
  1256.             DGopherListDoc::ProcessGopher(go, iview);
  1257.             go->fSaveToDisk= oldsave;
  1258.             }
  1259.         else  
  1260.             delete dlg;
  1261.         }
  1262.     return result;
  1263. }
  1264.  
  1265.  
  1266. void DGopherListDoc::PinWindow(Boolean turnon)
  1267.     fPinned= turnon;
  1268.     if (fStickpin) {
  1269.         if (fPinned) fStickpin->SetIcon( &gPushpinIn, true);
  1270.         else fStickpin->SetIcon( &gPushpinOut, true);
  1271.         }
  1272. }
  1273.  
  1274.  
  1275.  
  1276. Boolean DGopherListDoc::IsMyAction(DTaskMaster* action) 
  1277. {
  1278.     long  menuid;
  1279.     
  1280.     if (!action) return false;
  1281.     if (action->fSuperior && action->fSuperior->Id() == kViewKindMenu)
  1282.         menuid= action->fSuperior->Id();
  1283.     else 
  1284.         menuid= action->Id();
  1285.         
  1286.     switch (menuid) {
  1287.  
  1288.             case DApplication::kNew:
  1289.                 NewGopherDoc();
  1290.                 return true;
  1291.  
  1292.             case DApplication::kUndo:
  1293.                 Message(MSG_OK,"DGopherListDoc::Undo not ready.");
  1294.                 return true;
  1295.                 
  1296.             case DApplication::kCopy:
  1297.                 if (gClipGopher) gClipGopher->suicide();
  1298.                 gClipGopher= fGoview->SelectedGopher();
  1299.                 if (gClipGopher) {
  1300.                     gClipGopher= (DGopher*) gClipGopher->Clone();
  1301.                     gClipGopher->SetOwner(gClipGophers);
  1302.                     }
  1303.                 return true;
  1304.             
  1305.             case DApplication::kPaste:
  1306.                 AddGopherToView( gClipGopher);
  1307.                 return true;
  1308.  
  1309.             case DApplication::kCut:
  1310.                 CutClearSelection( true);
  1311.                 return true;
  1312.             case DApplication::kClear:
  1313.                 CutClearSelection( false);
  1314.                 return true;
  1315.             case DApplication::kSelectAll:
  1316.                 Message(MSG_OK,"DGopherListDoc::SelectAll not ready.");
  1317.                 return true;
  1318.             
  1319.             case cParentPopup:
  1320.                 {
  1321.                 DPopupList* pl= (DPopupList*) action;  
  1322.                 if (pl) PopData( pl->GetValue() - 1);                    
  1323.                 }
  1324.                 return true;
  1325.                 
  1326.             case cParentDrop:
  1327.                 //if (fParentPop) PopData( fParentPop->GetValue() - 1);        
  1328.                 Nlm_Beep();            
  1329.                 return true;
  1330.             
  1331.             case cPushpin:
  1332.                 PinWindow( !fPinned);
  1333.                 return true;
  1334.  
  1335.           case kViewChoiceMenu:
  1336.  
  1337. #ifndef BOBS_WIN_MAC                        
  1338.                 // we need a small dialog w/ our newest popup menu
  1339.                 (void) DGopherListDoc::GopherByViewDialog( this->fGoview->SelectedGopher(), fGolist);
  1340. #else
  1341.               {
  1342.                 short iview= action->Id() - kViewDefault;  
  1343.                 DGopher* go= this->fGoview->SelectedGopher();
  1344.                 if (go) DGopherListDoc::ProcessGopher(go, iview);
  1345.                 }
  1346. #endif
  1347.                 return true;
  1348.                 
  1349.             case kViewKindMenu:
  1350.                 switch(action->Id()) {
  1351.                     case kViewByDefault:
  1352.                             this->SortView(DGopherList::kSortByItem); return true;
  1353.                     case kViewByDate:
  1354.                             this->SortView(DGopherList::kSortByDate); return true;
  1355.                     case kViewBySize:
  1356.                             this->SortView(DGopherList::kSortBySize); return true;
  1357.                     case kViewByName:
  1358.                             this->SortView(DGopherList::kSortByName); return true;
  1359.                     case kViewByKind:
  1360.                             this->SortView(DGopherList::kSortByKind); return true;
  1361.                     case kViewByHost:
  1362.                             this->SortView(DGopherList::kSortByHost); return true;
  1363.                     case kViewAsText:
  1364.                     case kViewAsLink:
  1365.                             this->ToTextDoc( action->Id() == kViewAsLink); return true;
  1366.                     default: return false;
  1367.                     }
  1368.             
  1369.         default: 
  1370.             return false;
  1371.         }
  1372. }
  1373.             
  1374.  
  1375.  
  1376. Boolean DGopherListDoc::IsMyTask(DTask* theTask) 
  1377. {
  1378.     if (theTask->fKind == kGoListdoc) {
  1379.         ProcessTask( theTask);
  1380.         return true;
  1381.         }
  1382.     else 
  1383.         return DWindow::IsMyTask(theTask);
  1384. }
  1385.  
  1386. void DGopherListDoc::ProcessTask(DTask* theTask) 
  1387. {
  1388.     if (theTask->fNumber == cProcessGopher) {
  1389.         // ?? fix for obscure Motif bug from DGoAskDoc calling ProcessGopher...
  1390.         DGopher* aGoph= (DGopher*) theTask->fExtra;
  1391.         Boolean saveuse= this->fInUse;
  1392.         this->fInUse= true;
  1393.         DGopherListDoc::ProcessGopher( aGoph, aGoph->fViewchoice);
  1394.         this->fInUse= saveuse;
  1395.         //aGoph->suicide(); //??
  1396.         }
  1397.         
  1398.     else if (theTask->fNumber == cAdd && fParent) {
  1399.         fInUse= true;  
  1400.         fParent->ShowProgress();
  1401.         if (fParent->fInfoSize) {
  1402.         
  1403. #ifdef TRY_WITHOUT_THIS
  1404.             // this code, if it worked, would permit async display of gopher items
  1405.             // as each line/item is received.  but it is buggy, causing crashes
  1406.             // after a few fetches.  Rewrite at some point -- try Reverse StrStr(bufend,CRLF"+INFO")
  1407.             
  1408.             char * cbeg = fParent->fInfo;
  1409.             char * cend = cbeg + fParent->fInfoSize;
  1410.             char * cp = cend;
  1411.             char    clineend = '\012';  
  1412.                 
  1413.             if (StrStr( cbeg, CRLF"+INFO")) {
  1414.                 Boolean done = false;
  1415.                 do {
  1416.                     while (cp > cbeg && *cp != clineend) cp--; 
  1417.                     if (cp <= cbeg) done= true;
  1418.                     else if (StrNCmp( cp+1, "+INFO", 5) == 0) done= true;
  1419.                     else cp--;
  1420.                 } while (!done);
  1421.                 }
  1422.             else    // assume gopher- !? poor assumption?
  1423.                 while (cp > cbeg && *cp != clineend) cp--; 
  1424.             
  1425.             if (cp <= cbeg) cp= cend; 
  1426.             //char csave= *cp; *cp= 0;  // no more need for null term
  1427.             this->AddData(cbeg, cp - cbeg);  
  1428.             //*cp= csave;
  1429.             if (cp < cend) cp++; // skip the linefeed, which puts extra blank line in fDoc...
  1430.             
  1431.             long clen= cend - cp;
  1432.             cbeg= (char*) MemDup( cp, clen+1);
  1433.             //fParent->DeleteInfo();// this creates new fInfo
  1434.             if (fParent->fInfo) MemFree(fParent->fInfo); 
  1435.             fParent->fInfo= cbeg;   
  1436.             fParent->fInfoSize= clen; 
  1437.  
  1438.             if (fFirststuff>0) {
  1439.                 fGoview->SetColWidths(); //?!! required, some time after having real data
  1440.                 fFirststuff= 0;
  1441.                 }
  1442. #endif
  1443.  
  1444.             }
  1445.         
  1446.         if (fParent->ThreadProgress() == DGopher::kThreadDoneReading) {
  1447.             theTask->SetRepeat(false); // done w/ gopher fetch, dequeue this task
  1448.             this->ShowMessage("done reading");
  1449.             fInUse= false;  
  1450.             
  1451.                 // if TRY_WITHOUT_THIS is fixed, ?? change this
  1452.             char * cbeg = fParent->fInfo;
  1453.             char * cend = cbeg + fParent->fInfoSize;
  1454.             if (cend > cbeg) {
  1455.                 //*cend= 0; // no longer need null term
  1456.                 // ?? is bomb bug due to lack of end of data ??
  1457. #if 0
  1458.                 // still don't know where this bomb is coming from
  1459.                 // occurs ?? only when returning 1 gopher item in a gopherlist
  1460.                 // but beyond that ??? data looks okay, happens thru query item & thru go+ ask forms
  1461.                 
  1462.                 //char* kBombBugPatch = "i(Quick bug patch for obscure bomb)\t\tno.where.ever\t0"CRLF;    
  1463.                 
  1464.                 char *cp = cbeg;
  1465.                 for (short i= 0; i<2; i++) {
  1466.                     cp = StrChr(cp, kLF);
  1467.                     if (cp) cp++;
  1468.                     }
  1469.                 if (!cp) {
  1470.                     DGopher* ago= new DGopher();
  1471.                     ago->SetLink( *fParent->fInfo, fParent->fInfo);
  1472.                     char link1[512];
  1473.                     sprintf( link1, "%c%s\t%s\t%s\t%d\t%c",
  1474.                         ago->fType, (char*) ago->GetName(), (char*) ago->GetPath(), 
  1475.                         (char*) ago->GetHost(), ago->fPort, ' ');
  1476.                     delete ago;
  1477.                     
  1478.                     char *next= fParent->fInfo;
  1479.                     next= StrChr(next, kLF);
  1480.                     if (next) next++;
  1481.                     
  1482.                     char *tmp= StrDup(kBombBugPatch);
  1483.                 
  1484.                     StrExtendCat( &tmp, link1);
  1485.                     StrExtendCat( &tmp, next);
  1486.                     //StrExtendCat( &tmp, fInfo);
  1487.                     MemFree(fParent->fInfo);
  1488.                     fParent->fInfo= tmp;
  1489.                     fParent->fInfoSize= StrLen(tmp);
  1490.                     }
  1491. #endif
  1492.                     
  1493.                 this->AddData(cbeg, cend-cbeg);  
  1494.                      
  1495.                 if (fGolist->GetSize() < 1) { 
  1496.                     this->Close(); //this->suicide(); //delete this; 
  1497.                     return; 
  1498.                     }
  1499.                 else if (gFetchSingles && fGolist->GetSize() == 1) {
  1500.                     fGoview->OpenGopherLink(0);
  1501.                     this->Close(); // this works, but leaves un-updated window region on front window
  1502.                     return;
  1503.                     }
  1504.                     
  1505.                 fGoview->SetColWidths(); // !! required, some time after having real data
  1506.                 fGoview->Invalidate(); 
  1507.                 }
  1508.             else 
  1509.                 this->Close();  //this->suicide(); //delete this;  // dies here on mswin?
  1510.             }
  1511.         }
  1512.         
  1513.     else {
  1514.         DWindow::ProcessTask(theTask);
  1515.         }
  1516. }
  1517.  
  1518.  
  1519. void DGopherListDoc::Close()
  1520. {
  1521.     if (fParent &&  fParent->ThreadProgress() != DGopher::kThreadDoneReading) {
  1522.         // kill tcp connection !!!!!!!!
  1523.         fParent->CloseQuery();
  1524.         //fParent= NULL; // don't delete !?
  1525.         }
  1526.  
  1527.     if (!Nlm_EmptyRect(&fViewrect)) gGopherListDocRect= fViewrect;  
  1528.     if (gGopherDoc == this) gGopherDoc= NULL; // track front gopher doc/window
  1529.     fInUse= false;
  1530.     fPinned= false;
  1531.     DWindow::Close();
  1532. }
  1533.  
  1534. void DGopherListDoc::ResizeWin()
  1535. {
  1536.     DWindow::ResizeWin();
  1537.     if (fGoview && !Nlm_EmptyRect(&fViewrect)) gGopherListDocRect= fViewrect;  
  1538. }
  1539.  
  1540.  
  1541.  
  1542.  
  1543.  
  1544. void DGopherListDoc::MakeSubviews()
  1545. {
  1546.     if (!fGolist) fGolist= new DGopherList(fParent); //NULL
  1547.     fGolist->fDeleteObjects= DList::kDeleteObjects;
  1548.     if (!fGoview) {
  1549.         short width, height;
  1550.         Nlm_RecT        r;
  1551.         Nlm_PoinT        nps;
  1552.         this->GetNextPosition( &nps);
  1553.         nps.x= 0;  // where is that odd x-offset from ?
  1554.         this->SetNextPosition( nps);
  1555.         width = MAX( 40, gGopherListDocRect.right - gGopherListDocRect.left) 
  1556.                    - Nlm_vScrollBarWidth  - nps.x; 
  1557.         height= MAX( 60, gGopherListDocRect.bottom - gGopherListDocRect.top) 
  1558.                      - Nlm_hScrollBarHeight - nps.y;   
  1559. #ifdef WIN_MSWIN
  1560.         width  -= 16;
  1561.         height -= 24;
  1562. #endif
  1563.     
  1564.         fGoview= new DGolistView(0, this, fGolist, width, height);
  1565.         }
  1566.     else fGoview->fItems= fGolist;  
  1567.  
  1568.  
  1569. Boolean DGopherListDoc::CanReadFrom(DFile*& aFile)
  1570. {
  1571.         // callers have already checked that aFile exists and IsGopherDoc !!
  1572.         // ?? don't need this part now ??
  1573.     if (!aFile) {
  1574.         char *data = (char*) gFileManager->GetInputFileName(".go4",NULL); 
  1575.         if (data) aFile= new DFile( data, "r");
  1576.         }
  1577.     if (aFile) return true;
  1578.     else return false;
  1579. }
  1580.  
  1581.  
  1582. Boolean DGopherListDoc::ReadFrom(DFile* aFile)
  1583. {
  1584.     if (aFile) {
  1585.         gCursor->watch();
  1586.         this->SetTitle( (char*)aFile->GetShortname() );
  1587.  
  1588.         MakeSubviews();
  1589.         if (!fParent) {
  1590.             char docurl[1024];
  1591.             StrCpy(docurl, "file:///");
  1592.             StrNCat(docurl, (char*)aFile->GetName(), 1000);
  1593.             docurl[1023]= 0;
  1594.             fParent= DGopherList::GopherFromURL(docurl, strlen(docurl), fGolist);
  1595.             // ! GopherFromURL() sticks new gopher into list also !
  1596.             fGolist->fParentMenu= fParent;
  1597.             }
  1598.         
  1599.         aFile->OpenFile();
  1600.         ulong filelen;
  1601.         aFile->GetDataLength(filelen);
  1602.         char* buf= (char*) MemNew( filelen+1);
  1603.         aFile->ReadData( buf, filelen);
  1604.         this->AddData( buf, filelen);
  1605.         MemFree( buf);
  1606.         aFile->CloseFile();
  1607.         delete aFile;
  1608.         
  1609.         if (fGolist->GetSize() < 1) { return false; }
  1610.         fGoview->SetColWidths();     //?
  1611.         //fGoview->Invalidate();      //?? for ReplaceData only ??
  1612.         gCursor->arrow();
  1613.         fInUse= false;  
  1614.         return true;
  1615.         }
  1616.     else
  1617.         return false;
  1618. }
  1619.  
  1620.  
  1621.  
  1622. Boolean DGopherListDoc::CanReadFrom( DGopher* itsParent)
  1623. {
  1624.     if (itsParent) {
  1625.         fParent= itsParent;
  1626.         //if (fParent->fThreadState == DGopher::kThreadNotStarted) 
  1627.             fParent->ReadTask();   
  1628.         if (fParent->fInfoSize<10 && fParent->fThreadState == DGopher::kThreadDoneReading) {
  1629.             fParent->fThreadState= DGopher::kThreadNotStarted; // ! need to reset this somewhere for used gophers
  1630.             return false; 
  1631.             }
  1632.         else
  1633.             return true; 
  1634.         }
  1635.     else
  1636.         return false;
  1637. }
  1638.  
  1639.  
  1640. Boolean DGopherListDoc::ReadFrom( DGopher* itsParent)
  1641. {
  1642.     if (itsParent) {
  1643.         fParent= itsParent;
  1644.         this->SetTitle( (char*)fParent->ShortName());
  1645.         MakeSubviews();
  1646.         if (fParent->fThreadState == DGopher::kThreadNotStarted) 
  1647.             fParent->ReadTask();   
  1648.         if (fParent->fInfoSize<10 && fParent->fThreadState == DGopher::kThreadDoneReading) { 
  1649.             //this->Close(); //suicide();
  1650.             fParent->fThreadState= DGopher::kThreadNotStarted; // ! need to reset this somewhere for used gophers
  1651.             return false; 
  1652.             }
  1653.      
  1654.         DTask* aTask= newTask(cAdd, kGoListdoc); 
  1655.         aTask->SetRepeat(true);
  1656.         this->PostTask( aTask); 
  1657.         this->ShowMessage("opening link...");
  1658.         fInUse= true;
  1659.         return true; 
  1660.         }
  1661.     else
  1662.         return false;
  1663. }
  1664.  
  1665.  
  1666. // static
  1667. void DGopherListDoc::NewGopherDoc()
  1668. {
  1669.     gCursor->watch();
  1670.     DGopherListDoc* win= new DGopherListDoc( DGopherListDoc::kGoListdoc);
  1671.     //win->Open( theGo); 
  1672.     if (win) { 
  1673.         char* buf="+INFO: 1IUBio-Archive\t\tiubio.bio.indiana.edu\t71\t+\n"
  1674.                 "+INFO: 1GopherPup home\t1/IUBio-Software+Data/util/gopher/gopherpup\tiubio.bio.indiana.edu\t70\t+\n"
  1675.                 "+INFO: 1University of Minnesota Mother Gopher\t\tgopher.micro.umn.edu\t70\t+\n";
  1676.         ulong buflen = StrLen(buf);
  1677.  
  1678.         win->SetTitle( "Untitled" );
  1679.         win->MakeSubviews();
  1680.         win->AddData( buf, buflen);
  1681.         win->fGoview->SetColWidths(); //?
  1682.         win->Open( true);
  1683.         gCursor->arrow();
  1684.         }
  1685. }
  1686.  
  1687.  
  1688.  
  1689. void DGopherListDoc::Open( DFile* aFile)
  1690. {
  1691.     if ( ReadFrom( aFile) )
  1692.         Open( true);
  1693.     else
  1694.         Close(); //suicide();
  1695. }
  1696.  
  1697. void DGopherListDoc::Open( DGopher* itsParent)
  1698. {
  1699.     if ( ReadFrom( itsParent) )
  1700.         Open( true);
  1701.     else
  1702.         Close(); 
  1703. }
  1704.  
  1705.  
  1706. void DGopherListDoc::Open( Boolean haveData)
  1707. {
  1708.     if (!haveData) {
  1709.         Close();
  1710.         return;
  1711.         }
  1712.  
  1713. #if 1                
  1714.     // short minwidth= Nlm_StringWidth( (char*)fParentGo->ShortName());
  1715.     this->Select(); // ?? for motif
  1716.     Nlm_ResizeWindow( (Nlm_GraphiC)fWindow, kWinDragHeight, kWinScrollWidth,
  1717.                          kWinMinWidth, kWinExtraHeight);
  1718. #endif
  1719.  
  1720.     fSaveHandler= this; // replace fGoview's handler w/ us
  1721.     if (fStatus && fGolist) fGolist->SetStatus( fStatus);
  1722.     if (fParentlist && fParentPop) {
  1723.         char * name;
  1724.         short i, n= fParentlist->GetSize();
  1725.         if (fParent) name= (char*)fParent->ShortName();
  1726.         else name= "Current link";
  1727.         fParentPop->AddItem(name);
  1728.         for (i= n-1; i>=0; i--) {
  1729.             DGopher* go= NULL;
  1730.             DGopherList* golist= (DGopherList*) fParentlist->At(i);
  1731.             if (golist) go= golist->fParentMenu;
  1732.             if (go) fParentPop->AddItem((char*)go->ShortName());   
  1733.             }
  1734.         }
  1735.  
  1736.     fGoview->Invalidate();         // force redraw !?
  1737.     fGoview->SetOffset(0, 0); //  zero the scrollbars
  1738.     fGoview->SetTop(0);                 //  reset data scroll offset 
  1739.  
  1740.     short i, n= fGolist->GetSize();
  1741.     for (i=0; i<n; i++) 
  1742.         fGoview->SetLineHeight( i, fGolist->GopherAt(i));
  1743.  
  1744.     gGopherDoc= this; // track front gopher doc/window
  1745.     fGoview->SizeToSuperview( this, true, true); //??
  1746.     DWindow::Open();
  1747. }
  1748.  
  1749.  
  1750. void DGopherListDoc::UpdateListSize()
  1751. {        
  1752.     short nnew, nold, i;
  1753.     
  1754.     nold= fGoview->GetMaxRows();  
  1755.     nnew= fGolist->GetSize();
  1756.     //fGoview->SetTableSize(nnew, 9);
  1757.     fGoview->ChangeRowSize( -1, nnew-nold); // was (nold, .. -1 prevents unneeded redraw ?
  1758. }
  1759.  
  1760. void DGopherListDoc::AddData(char* gopherData, long datalen)
  1761. {        
  1762.     short nnew, nold, i;
  1763.     
  1764.     nold= fGolist->GetSize();
  1765.     fGolist->ReadLinks(gopherData, datalen);
  1766.     nnew= fGolist->GetSize();
  1767.     //fGoview->SetTableSize(nnew, 9);
  1768.     fGoview->ChangeRowSize( -1, nnew-nold); // was (nold, .. -1 prevents unneeded redraw ?
  1769. }
  1770.  
  1771. void DGopherListDoc::Activate()
  1772. {    
  1773.     SetViewMenu(true); 
  1774.     if (gLockWinMenuItem)  gLockWinMenuItem->SetStatus( fInUse || fPinned);        
  1775.     gGopherDoc= this; // track front gopher doc/window
  1776.     DWindow::Activate();
  1777. }
  1778.  
  1779. void DGopherListDoc::Deactivate()
  1780. {    
  1781.     SetViewMenu(false); 
  1782.     if (gLockWinMenuItem)  gLockWinMenuItem->SetStatus(false);
  1783.     //if (gGopherDoc == this) gGopherDoc= NULL; 
  1784.     // ^^ can't do now, Ask window needs this, and when it comes out, this goes... 
  1785.     DWindow::Deactivate();
  1786. }
  1787.  
  1788. void DGopherListDoc::SetViewMenu(Boolean activate)
  1789. {         
  1790. #ifndef BOBS_WIN_MAC                        
  1791.   //gWindowManager->SetLastActive(this); // motif don't track active windows too good, needs help
  1792. #else                        
  1793.                         // THIS IS NO GOOD ON XWIN, and probably NO GOOD on MSWIN
  1794.                         // Vibrant currently has no way of removing single menu items
  1795.                         // except for Mac.  Only option for others seems to be removal
  1796.                         // of entire (sub) menu, with no way to replace w/ a new menu
  1797.                         // in *same* position !!!
  1798.    if (gViewChoiceMenu) {
  1799.          short item= kViewDefault;
  1800.          gViewChoiceMenu->Reset();  
  1801.          gViewChoiceMenu->AddItem( item, "default");
  1802.          DGopher* go= fGoview->SelectedGopher();
  1803.          if (activate && go && go->fViews) {
  1804.             long i, n= go->fViews->GetSize();
  1805.             for (i= 0; i<n; i++) {
  1806.                 char *cp, smenu[256];
  1807.                 item++;
  1808.                 DGopherItemView* giv= (DGopherItemView*) go->fViews->At(i);
  1809.                 StrNCpy(smenu, (char*) giv->ViewVal(), 255);
  1810.                 //cp= smenu; 
  1811.                 //while (cp= strchr(cp, '/')) *cp= '_';
  1812.                 gViewChoiceMenu->AddItem( item, smenu);
  1813.                 //gViewChoiceMenu->EnableItem( item); 
  1814.                 }
  1815.              }
  1816.      }
  1817. #endif
  1818. }
  1819.  
  1820.  
  1821. void DGopherListDoc::AddGopherToView( DGopher* aGopher)
  1822. {    
  1823.     if (aGopher) {
  1824.         short aRow = fGoview->GetSelectedRow();
  1825.         if (aRow==0) aRow= fGolist->GetSize();
  1826.         aRow++;    // insert after...
  1827.         aGopher= (DGopher*) aGopher->Clone(); 
  1828.         aGopher->SetOwner(fGolist); 
  1829.         fGolist->InsertBefore( aRow, (DObject*) aGopher);
  1830.         fGoview->ChangeRowSize( aRow, 1);  
  1831.         Dirty(); // !? this needs to track the fGolist, which can be popped/pushed
  1832.         }
  1833. }
  1834.  
  1835.  
  1836. void DGopherListDoc::CutClearSelection( Nlm_Boolean saveCut)
  1837. {    
  1838.     short aRow = fGoview->GetSelectedRow();
  1839.     if (aRow == DTableView::kNoSelection) return;
  1840.     DGopher* aGopher= fGolist->GopherAt(aRow);
  1841.     if (saveCut && aGopher) {
  1842.         if (gClipGopher) gClipGopher->suicide();
  1843.         gClipGopher= aGopher;
  1844.         gClipGopher= (DGopher*) gClipGopher->Clone();        
  1845.         gClipGopher->SetOwner(gClipGophers); 
  1846.         }
  1847.     fGolist->AtDelete( aRow); // this kills aRow gopher
  1848.     fGoview->SetEmptySelection(false);
  1849.     fGoview->ChangeRowSize( aRow, -1);  
  1850.     Dirty();  
  1851. }
  1852.  
  1853.  
  1854. void DGopherListDoc::WriteTo(DFile* aFile)
  1855. {
  1856.     char     line[512];
  1857.     char    *data;
  1858.     Boolean    callerOwnsFile= (aFile != NULL);
  1859.     
  1860.     if (!callerOwnsFile) {
  1861.         data= this->GetTitle();
  1862.         sprintf(line, "%s.go4", data);
  1863.         MemFree(data);
  1864.         data= (char*) gFileManager->GetOutputFileName(line);  
  1865.         if (data) aFile= new DFile( data, "w", "TEXT", "IGo4");
  1866.         }
  1867.         
  1868.     if (aFile) {
  1869.         gCursor->watch();
  1870.         data= fGolist->WriteLinks();
  1871.         ulong    dlen= StrLen(data);
  1872.         
  1873.         aFile->OpenFile();
  1874.         aFile->WriteData(data, dlen);
  1875.         aFile->CloseFile();
  1876.         MemFree(data);
  1877.         if (!callerOwnsFile) delete aFile; 
  1878.         this->NotDirty();
  1879.         gCursor->arrow();
  1880.         }    
  1881. }
  1882.  
  1883.  
  1884.  
  1885.  
  1886.  
  1887.  
  1888.  
  1889.  
  1890.  
  1891.  
  1892.  
  1893.  
  1894. //class DGolistView : public DTableView
  1895.  
  1896.     
  1897. DGolistView::DGolistView(long id, DView* itsSuperior, DGopherList* itsItems, 
  1898.     short pixwidth, short pixheight):
  1899.     DTableView( id, itsSuperior, pixwidth, pixheight, 0, 9, 50, 36),
  1900.     fItems(itsItems), fDragGopher(NULL), fDragging(false)
  1901. {    
  1902.     this->SetSlateBorder(false);
  1903.   this->SetResize( DView::relsuper, DView::relsuper);
  1904.  
  1905.     ////>>nevermore>>////this->SetColWidths(); // BAD call HERE ON PPC !!!
  1906.     if (gGoviewFont == NULL) gGoviewFont= Nlm_programFont;
  1907.     if (gTextFont == NULL) gTextFont= Nlm_programFont;
  1908.     this->SetTableFont(gGoviewFont);
  1909.     MakeSmallFont();
  1910. }
  1911.  
  1912.  
  1913. void DGolistView::SizeToSuperview( DView* super, Boolean horiz, Boolean vert)
  1914. {
  1915.         // size only lower and right sides == leave top area...
  1916. #if 0
  1917. #ifdef WIN_MOTIF
  1918.     //DTableView::SizeToSuperview( super, horiz, vert);
  1919. #if 0
  1920.     Nlm_RecT r, myr;
  1921.     super->ViewRect(r);
  1922.     GetPosition(myr);
  1923.     if (horiz) myr.right  = r.right - myr.left; // - r.left
  1924.     if (vert)  myr.bottom = r.bottom - myr.top; //- r.top 
  1925.     //this->Select(); // motif requires ?
  1926.     SetPosition( myr);
  1927. #endif
  1928. #else    
  1929.     Nlm_RecT r, myr;
  1930.     super->ViewRect(r);
  1931.     GetPosition(myr); // ViewRect(myr); <<!NO, diff from GetPos/SetPos
  1932.     if (horiz) myr.right= (r.right - r.left) +1;
  1933.     // myr.right -= (Nlm_vScrollBarWidth - 8); // mswin fix ?? 
  1934.     if (vert) myr.bottom =  (r.bottom - r.top)  +1; 
  1935.     // myr.bottom -= (Nlm_hScrollBarHeight + 10); // mswin fix ??
  1936.     SetPosition( myr);
  1937. #endif
  1938. #endif
  1939.     this->FindLocation(); //?? added 14Mar94, gopher tables were doing this
  1940. }
  1941.  
  1942. void DGolistView::Resize(DView* superview, Nlm_PoinT sizechange)
  1943. {
  1944.     DTableView::Resize( superview, sizechange);
  1945. }
  1946.  
  1947.  
  1948.  
  1949. void DGolistView::Hold(Nlm_PoinT mouse)
  1950. {
  1951.     DTableView::Hold(mouse);
  1952. }
  1953.  
  1954. //Local DGopher* gDragGopher = NULL;
  1955.  
  1956. void DGolistView::Drag(Nlm_PoinT mouse)
  1957. {
  1958.     short row, col;
  1959.     DTableView::Drag(mouse);
  1960.  
  1961.     // this is called on drag, if click/release are ignored
  1962.     //PointToCell(mouse, row, col);
  1963.     //fDragGopher= fItems->GopherAt(row);
  1964.     fDragging= true;
  1965.     gCursor->plus();
  1966. }
  1967.  
  1968. void DGolistView::Release(Nlm_PoinT mouse)
  1969. {
  1970.     DTableView::Release(mouse);
  1971.     gCursor->arrow();
  1972.     
  1973.     //short row, col;
  1974.     //PointToCell(mouse, row, col);
  1975.     //DGopher* ag= fItems->GopherAt(row);
  1976.     
  1977.     DWindow* win= gWindowManager->WhichWindow( mouse);
  1978.     if (fDragGopher && fDragging && win && win != this->GetWindow()) {
  1979.         if (win->Id() == DGoLinkedTextDoc::kGoLitextdoc) {
  1980.             ((DGoLinkedTextDoc*) win)->LinkToSelection( fDragGopher);
  1981.             Nlm_Beep();
  1982.             }
  1983.         else if (win->Id() == DGopherListDoc::kGoListdoc) {
  1984.             ((DGopherListDoc*) win)->AddGopherToView( fDragGopher);
  1985.             Nlm_Beep();
  1986.             }
  1987.         }
  1988.     fDragging= false;
  1989.     fDragGopher= NULL;
  1990. }
  1991.  
  1992.  
  1993. void DGolistView::OpenGopherLink(short gopherItem)
  1994. {
  1995.     DGopher* ag= fItems->GopherAt(gopherItem); 
  1996.     if (ag) {
  1997.         Boolean nooption= false;
  1998.         Boolean optionIsOn= gKeys->option();
  1999.         Boolean oneKnownView = (ag->fViews && ag->fViews->GetSize() < 2);
  2000.  
  2001.         if (oneKnownView) {
  2002.             unsigned short lastrank = 0;
  2003.             DGopherItemView* giv= (DGopherItemView*) ag->fViews->First();
  2004.             char * viewkind= (char*)giv->Kind();
  2005.             DGopherMap* aMapper= gGopherMap->MatchHandlerKind( lastrank, viewkind); 
  2006.             if (!aMapper) oneKnownView= false;
  2007.             }
  2008.             
  2009.         nooption= (ag->fType == kTypeFolder
  2010.             || ag->fType == kTypeQuery  // ???
  2011.           || ag->fIsPlus != kGopherPlusYes
  2012.           || oneKnownView 
  2013.           ); 
  2014.           
  2015.         if (!nooption && DGopherListDoc::gOptionIsOn) 
  2016.             optionIsOn= !optionIsOn;
  2017.                     
  2018.         ((DGopherListDoc*)fSuperior)->ShowMessage("opening link...");
  2019.         if (optionIsOn) 
  2020.             (void) DGopherListDoc::GopherByViewDialog(ag, ag->fOwnerList);
  2021.         else  {
  2022.             short itsViewchoice= DGopherListDoc::DefaultGopherView(ag);
  2023.             DGopherListDoc::ProcessGopher( ag, itsViewchoice);
  2024.             }
  2025.         }
  2026. }
  2027.  
  2028.  
  2029.  
  2030.  
  2031. void DGolistView::DoubleClickAt(short row, short col)
  2032. {
  2033.     if (gDoubleClicker) OpenGopherLink(row);
  2034. }
  2035.  
  2036. void DGolistView::SingleClickAt(short row, short col)
  2037. {
  2038.     DTableView::SingleClickAt(row,  col);
  2039.     ((DGopherListDoc*)fSuperior)->SetViewMenu();
  2040.     fDragGopher= fItems->GopherAt(row);
  2041.     gWindowManager->SetCurrent((DWindow*)fSuperior); // motif needs help
  2042.     if (gSingleClicker) OpenGopherLink(row);
  2043. }
  2044.  
  2045.  
  2046. DGopher* DGolistView::SelectedGopher()
  2047. {
  2048.     if (GetSelectedRow() != kNoSelection) 
  2049.         return fItems->GopherAt( GetSelectedRow());
  2050.     else 
  2051.         return NULL;
  2052. }
  2053.  
  2054.  
  2055. #define USE_MULTI_LINES 1
  2056.  
  2057. void DGolistView::SetLineHeight( short item, DGopher* theGo)
  2058. {
  2059. #if NOTNOW_USE_MULTI_LINES
  2060.   short icowidth;
  2061.   Nlm_SelectFont(fFont);
  2062.     switch (gIconSize) {
  2063.         case 0: icowidth= 14; break;
  2064.         case 1: icowidth= 20; break;
  2065.         default:
  2066.         case 2: icowidth= 36; break;
  2067.         }
  2068.     short nlines = 1;
  2069.     //if (gShowURL||gShowDate||gShowSize||gShowHost||gShowPort||gShowPath||gShowAdmin)
  2070.     if (gShowExtras)
  2071.         nlines++;
  2072.     short height= nlines * Nlm_LineHeight();
  2073.     if (theGo) height += theGo->HeightAbstract();
  2074.     height= MAX( icowidth, height);  // Nlm_FontHeight
  2075.     this->SetItemHeight( item, 1, height);
  2076. #endif
  2077. }
  2078.  
  2079.  
  2080.  
  2081. void DGolistView::SetColWidths()
  2082. {
  2083.     enum { kPlusWidth = 0, kTitleWidth = 1200 }; // == 10
  2084.     
  2085.     short icowidth, height, nlines, wid;
  2086.  
  2087.     nlines = 1;
  2088.     //if (gShowURL||gShowDate||gShowSize||gShowHost||gShowPort||gShowPath||gShowAdmin)
  2089.     if (gShowExtras)
  2090.         nlines++;
  2091.         
  2092.     //Nlm_WindoW w= Nlm_SavePort( GetNlmObject());
  2093.     SelectFont();
  2094.  
  2095.     if (fItems && fItems->GetSize() > 0) 
  2096.         this->SetTableSize( fItems->GetSize(), 3);  // was 9 cols
  2097.     
  2098.     switch (gIconSize) {
  2099.         case 0: icowidth= 14; break;
  2100.         case 1: icowidth= 20; break;
  2101.         default:
  2102.         case 2: icowidth= 36; break;
  2103.         }
  2104.         
  2105.     height= nlines * Nlm_LineHeight();  // Nlm_FontHeight
  2106. #if USE_MULTI_LINES
  2107.     if (fItems) {
  2108.         short i, n = fItems->GetSize();
  2109.         for (i= 0; i<n; i++) {
  2110.             DGopher* go= fItems->GopherAt(i);
  2111.             this->SetItemHeight( i, 1, MAX( icowidth, height + go->HeightAbstract()));
  2112.             }
  2113.         }
  2114.     else
  2115. #endif
  2116.         this->SetItemHeight( 0, GetMaxRows(), MAX( icowidth, height));
  2117.         
  2118.     this->SetItemWidth( 0, 1, icowidth+2);         
  2119.     this->SetItemWidth( 1, 1, kPlusWidth);  
  2120.     //wid= Nlm_StringWidth("A long title to measure for max width");
  2121.     this->SetItemWidth( 2, 1, kTitleWidth); 
  2122. }
  2123.  
  2124.  
  2125. void DGolistView::DrawCell(Nlm_RecT r, short row, short col)
  2126. {
  2127. #define gShowPlus  1
  2128.     // need a DTableView field to handle cell rect insets !
  2129.     //if (col) 
  2130.     r.left += 2; // quick fix for cells against each
  2131.     DGopher* ag= fItems->GopherAt(row); 
  2132.     if (ag) switch (col) {
  2133.     
  2134.         case 0: 
  2135.             ag->DrawIcon(r, gIconSize); 
  2136.             break;   
  2137.  
  2138. #if 0        
  2139.         case 1: { 
  2140.             Nlm_RecT     lr;
  2141.             lr= r;
  2142.             lr.bottom= lr.top + Nlm_LineHeight();
  2143.             ag->DrawPlus( lr); 
  2144.             } 
  2145.             break;
  2146. #endif
  2147.         
  2148.         case 2:  {
  2149.             Nlm_RecT     lr;
  2150.             Nlm_PoinT pt;
  2151.             short lineheight, absHeight = 0, nlines = 1;
  2152.             
  2153. #if 1
  2154.             lineheight= Nlm_LineHeight(); // store this const somewhere !?
  2155. #else
  2156.             //if (gShowURL||gShowDate||gShowSize||gShowHost||gShowPort||gShowPath||gShowAdmin)
  2157.             if (gShowExtras)    nlines++;
  2158.             if (ag->fAbstract) absHeight= ag->HeightAbstract(); // this can drag on draw time !!
  2159.             lineheight=  (r.bottom - r.top - absHeight) / nlines;
  2160. #endif
  2161.  
  2162.             lr= r;
  2163.             lr.bottom= lr.top + lineheight;
  2164.             ag->DrawTitle(lr); 
  2165.             
  2166.             if (ag->fType != kTypeNote && gShowExtras) {
  2167.               //(gShowURL||gShowDate||gShowSize||gShowHost||gShowPort||gShowPath||gShowAdmin)) 
  2168.               
  2169.                 lr.top = lr.bottom; 
  2170.                 lr.bottom= lr.top + lineheight;
  2171.                 Nlm_MoveTo(lr.left, lr.top);
  2172.               Nlm_SelectFont(gSmallFont); // this is a HACK !!
  2173.                 if (gShowDate) { ag->DrawDate(lr); Nlm_GetPen(&pt); lr.left = pt.x + 5;  } 
  2174.                 if (gShowSize) { ag->DrawSize(lr); Nlm_GetPen(&pt); lr.left = pt.x + 5;  } 
  2175.                 if (gShowHost) { ag->DrawHost(lr); Nlm_GetPen(&pt); lr.left = pt.x + 5;  } 
  2176.                 if (gShowPort) { ag->DrawPort(lr); Nlm_GetPen(&pt); lr.left = pt.x + 5;  } 
  2177.                 if (gShowPath) { ag->DrawPath(lr); Nlm_GetPen(&pt); lr.left = pt.x + 5;  } 
  2178.                 if (gShowURL)  { ag->DrawURL(lr); Nlm_GetPen(&pt); lr.left = pt.x + 5;  } 
  2179.                 if (gShowAdmin) { ag->DrawAdmin(lr); Nlm_GetPen(&pt); lr.left = pt.x + 5;  } 
  2180.                 if (gShowPlus) { ag->DrawPlus(lr); Nlm_GetPen(&pt); lr.left = pt.x + 5;  } 
  2181.                 }
  2182.             
  2183. #if USE_MULTI_LINES
  2184.             if (gShowAbstract && ag->fAbstract) {
  2185.                 lr.left= r.left;
  2186.                 lr.top = lr.bottom; 
  2187.                 lr.bottom= r.bottom; //lr.top + absHeight; 
  2188.                 Nlm_MoveTo(lr.left, lr.top);
  2189.                 ag->DrawAbstract( lr);
  2190.                 }
  2191. #endif
  2192.  
  2193.             SelectFont(); // double HACK !!
  2194.             }
  2195.             break;
  2196.  
  2197.         }
  2198. }
  2199.  
  2200.  
  2201.  
  2202.  
  2203. #if 0
  2204.                 ////////// old view
  2205.  
  2206. void DGolistView::SetColWidths()
  2207. {
  2208.     short icowidth, height, wid;
  2209.  
  2210.     //Nlm_WindoW w= Nlm_SavePort( GetNlmObject());
  2211.   Nlm_SelectFont(fFont);
  2212.  
  2213.     if (fItems && fItems->GetSize() > 0) 
  2214.         this->SetTableSize( fItems->GetSize(), 9);
  2215.     
  2216.     switch (gIconSize) {
  2217.         case 0: icowidth= 14; break;
  2218.         case 1: icowidth= 20; break;
  2219.         default:
  2220.         case 2: icowidth= 36; break;
  2221.         }
  2222.     height= icowidth; //Max( icowidth, Nlm_LineHeight());  // Nlm_FontHeight
  2223.     this->SetItemHeight( 0, fMaxRows, height);
  2224.  
  2225.     this->SetItemWidth( 0, 1, icowidth);     // go->WidthIcon(size)
  2226.     this->SetItemWidth( 1, 1, 10);     // go->WidthPlus()
  2227.     wid= Nlm_StringWidth("A long title to measure for max width");
  2228.     this->SetItemWidth( 2, 1, wid); // go->WidthTitle()
  2229.     
  2230.     wid= (gShowDate) ? Nlm_StringWidth(" 30Jan94 ") : 0;
  2231.     this->SetItemWidth( 3, 1, wid);      
  2232.     wid= (gShowSize) ? Nlm_StringWidth(" 1234kb ") : 0;
  2233.     this->SetItemWidth( 4, 1, wid);      
  2234.     wid= (gShowHost) ? Nlm_StringWidth(" gopher.some.where.edu ") : 0;
  2235.     this->SetItemWidth( 5, 1, wid);  
  2236.     wid= (gShowPort) ? 30 : 0;
  2237.     this->SetItemWidth( 6, 1, 30);          
  2238.     wid= (gShowPath) ? Nlm_StringWidth(" /some/path/to/timbuktu ") : 0;;
  2239.     this->SetItemWidth( 7, 1, wid);      
  2240.     wid= (gShowAdmin) ? Nlm_StringWidth(" gtirebiter@some.fancy.mailhost ") : 0;
  2241.     this->SetItemWidth( 8, 1, wid);  
  2242.     //Nlm_RestorePort( w); // bombing here w/ GetSize()==1 ???
  2243. }
  2244.  
  2245.  
  2246. void DGolistView::DrawCell(Nlm_RecT r, short row, short col)
  2247. {
  2248.     // need a DTableView field to handle cell rect insets !
  2249.             
  2250.     if (col) r.left += 2; // quick fix for cells against each
  2251.     DGopher* ag= fItems->GopherAt(row); 
  2252.     if (ag) switch (col) {
  2253.         case 0: ag->DrawIcon(r, gIconSize); break;   
  2254.         case 1: ag->DrawPlus(r); break;
  2255.         
  2256.         case 2: ag->DrawTitle(r); break;
  2257.         
  2258.         case 3: ag->DrawDate(r); break;
  2259.         case 4: ag->DrawSize(r); break;
  2260.         case 5: ag->DrawHost(r); break;
  2261.         case 6: ag->DrawPort(r); break;
  2262.         case 7: ag->DrawPath(r); break;
  2263.         case 8: ag->DrawAdmin(r); break;
  2264.         //case 9: ag->DrawKind(r); break;
  2265.         }
  2266. }
  2267.     //////////////// old view
  2268. #endif 
  2269.  
  2270.